/***********************************************
 This file is part of redia-lib-utils-ios
.
 
 Copyright (c) 2014 Redia A/S
 
 Redia-library-app-ios is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.
 
 Redia-library-app-ios is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with redia-library-app-ios.  If not, see <http://www.gnu.org/licenses/>.
 
 *********************************************** */

#import "LazyLoadManager.h"

@interface LazyLoadManager()

/**
 This is a map of owner -> list of connections.
 The owner can be any object type (non native datatype).
 */
@property (strong, nonatomic) NSMutableDictionary *ownedConnections;

/**
 This is a simple list of orphaned (without an owner) connections.
 */
@property (strong, nonatomic) NSMutableArray *orphanedConnections;

@end

@implementation LazyLoadManager

SINGLETON_IMPL_GCD(LazyLoadManager)

- (id)init
{
    self = [super init];
    if (self) {
        self.ownedConnections = [NSMutableDictionary new];
        self.orphanedConnections = [NSMutableArray new];
    }
    return self;
}

#pragma mark - Starting loaders

- (void)lazyLoadUIImageFromUrl:(NSString*)url setScaleforRetina:(BOOL)setScaleforRetina onSuccess:(LLSuccessBlock)successBlock onError:(LLErrorBlock)errorBlock
{
    [self lazyLoadUIImageFromUrl:url withOwner:nil setScaleforRetina:setScaleforRetina onSuccess:successBlock onError:errorBlock onCancel:nil];
}

-(void)lazyLoadUIImageFromUrl:(NSString *)url withOwner:(id)owner setScaleforRetina:(BOOL)setScaleforRetina onSuccess:(LLSuccessBlock)successBlock onError:(LLErrorBlock)errorBlock
{
    [self lazyLoadUIImageFromUrl:url withOwner:owner setScaleforRetina:setScaleforRetina onSuccess:successBlock onError:errorBlock onCancel:nil];
}

- (void)lazyLoadUIImageFromUrl:(NSString*)url withOwner:(id)owner setScaleforRetina:(BOOL)setScaleforRetina onSuccess:(LLSuccessBlock)successBlock onError:(LLErrorBlock)errorBlock onCancel:(LLCancelBlock)cancelBlock
{
    LazyLoadConnection *connection = [[LazyLoadConnection alloc] initWithUrl:url setScaleforRetina:setScaleforRetina onSuccess:successBlock onError:errorBlock onCancel:cancelBlock];
    if (owner) {
        NSValue *key = [NSValue valueWithPointer:(__bridge const void *)(owner)];
        if ([self.ownedConnections objectForKey:key]) {
            [[self.ownedConnections objectForKey:key] addObject:connection];
        }
        else {
            [self.ownedConnections setObject:[NSMutableArray arrayWithObject:connection] forKey:key];
        }
    }
    else {
        [self.orphanedConnections addObject:connection];
    }
    [connection start];
}


#pragma mark - Cancelling connections

- (void)cancelConnectionsForOwner:(id)owner
{
    NSValue *key = [NSValue valueWithPointer:(__bridge const void *)(owner)];
    NSMutableArray *connections = [self.ownedConnections objectForKey:key];
    if (connections) {
        for (LazyLoadConnection *connection in connections) {
            [connection cancel];
        }
        [self.ownedConnections removeObjectForKey:key];
    }
}

- (void)cancelOrphanedConnections
{
    for (LazyLoadConnection *connection in self.orphanedConnections) {
        [connection cancel];
    }
    [self.orphanedConnections removeAllObjects];
}

- (void)cancelAllConnections
{
    for (LazyLoadConnection *connection in self.orphanedConnections) {
        [connection cancel];
    }
    for (NSValue *key in [self.ownedConnections allKeys]) {
        for (LazyLoadConnection *connection in [self.ownedConnections objectForKey:key]) {
            [connection cancel];
        }
    }
    [self.orphanedConnections removeAllObjects];
    [self.ownedConnections removeAllObjects];
}

- (void)cancelConnection:(LazyLoadConnection *)connection
{
    [self removeConnection:connection];
    [connection cancel];
}

- (void)removeConnection:(LazyLoadConnection *)connection
{
    // Search for the connection in the list of orphaned connections.
    NSUInteger index = [self.orphanedConnections indexOfObject:connection];
    if (index != NSNotFound) {
        [self.orphanedConnections removeObjectAtIndex:index];
        return;
    }
    
    // Seeing as the connection wasn't found amongst the orphaned connections, we
    // have to perform a search through the owned connections.
    for (NSValue *key in [self.ownedConnections allKeys]) {
        NSMutableArray *connections = [self.ownedConnections objectForKey:key];
        NSUInteger index = [connections indexOfObject:connection];
        if (index != NSNotFound) {
            [connections removeObject:connection];
            if ([connections count] == 0) {
                [self.ownedConnections removeObjectForKey:key];
            }
            return;
        }
    }
}

@end
